#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Android字符串资源到鸿蒙字符串资源转换工具
支持GUI和CLI两种模式
"""

import os
import json
import xml.etree.ElementTree as ET
import argparse
import logging
import re
from typing import Dict, List, Tuple, Set, Optional
from pathlib import Path
import tkinter as tk
from tkinter import ttk, filedialog, messagebox, scrolledtext
import threading


class ResourceMigrator:
    """资源迁移核心类"""
    
    def __init__(self):
        self.logger = self._setup_logger()
        self.resource_map = {}  # {language: {name: value}}
        
    def _setup_logger(self) -> logging.Logger:
        """设置日志记录器"""
        logger = logging.getLogger('ResourceMigrator')
        logger.setLevel(logging.INFO)
        
        if not logger.handlers:
            handler = logging.StreamHandler()
            formatter = logging.Formatter(
                '%(asctime)s - %(levelname)s - %(message)s'
            )
            handler.setFormatter(formatter)
            logger.addHandler(handler)
            
        return logger
    
    def find_strings_files(self, res_dir: str) -> Dict[str, str]:
        """
        在res目录中递归查找所有strings.xml文件
        
        Args:
            res_dir: Android资源目录路径
            
        Returns:
            Dict[str, str]: 语言代码到strings.xml文件路径的映射
        """
        strings_files = {}
        res_path = Path(res_dir)
        
        if not res_path.exists() or not res_path.is_dir():
            self.logger.error(f"资源目录不存在或不是目录: {res_dir}")
            return strings_files
            
        # 递归搜索所有values目录
        for values_dir in res_path.rglob("values*"):
            if not values_dir.is_dir():
                continue
                
            # 查找strings.xml或strings开头的xml文件
            xml_files = list(values_dir.glob("strings*.xml"))
            if not xml_files:
                continue
                
            # 使用第一个找到的strings文件
            strings_file = xml_files[0]
            
            # 解析语言代码
            dir_name = values_dir.name
            if dir_name == "values":
                lang_code = "base"
            elif dir_name.startswith("values-"):
                lang_code = dir_name[7:]  # 移除"values-"前缀
                # 处理特殊的语言代码格式
                lang_code = self._normalize_language_code(lang_code)
            else:
                continue
                
            strings_files[lang_code] = str(strings_file)
            self.logger.info(f"找到字符串文件: {lang_code} -> {strings_file}")
            
        return strings_files
    
    def _normalize_language_code(self, lang_code: str) -> str:
        """标准化语言代码"""
        # 处理Android格式到鸿蒙格式的转换
        lang_map = {
            'zh-rCN': 'zh_CN',
            'zh-rTW': 'zh_TW', 
            'zh-rHK': 'zh_HK',
            'en-rUS': 'en_US',
            'en-rGB': 'en_GB',
        }
        
        # 如果包含-r格式，转换为_格式
        if '-r' in lang_code:
            return lang_map.get(lang_code, lang_code.replace('-r', '_'))
        elif '-' in lang_code:
            return lang_code.replace('-', '_')
        
        return lang_code
    
    def parse_strings_xml(self, file_path: str) -> Dict[str, str]:
        """
        解析strings.xml文件
        
        Args:
            file_path: XML文件路径
            
        Returns:
            Dict[str, str]: 字符串资源字典
        """
        try:
            tree = ET.parse(file_path)
            root = tree.getroot()
            
            strings = {}
            for string_elem in root.findall('string'):
                name = string_elem.get('name')
                value = string_elem.text or ''
                
                if name:
                    # 处理XML转义字符
                    value = self._unescape_xml(value)
                    strings[name] = value
                    
            self.logger.info(f"从 {file_path} 解析出 {len(strings)} 个字符串")
            return strings
            
        except ET.ParseError as e:
            self.logger.error(f"XML解析错误 {file_path}: {e}")
            return {}
        except Exception as e:
            self.logger.error(f"处理文件 {file_path} 时出错: {e}")
            return {}
    
    def _unescape_xml(self, text: str) -> str:
        """反转义XML字符"""
        if not text:
            return text
            
        text = text.replace('&lt;', '<')
        text = text.replace('&gt;', '>')
        text = text.replace('&amp;', '&')
        text = text.replace('&quot;', '"')
        text = text.replace('&apos;', "'")
        
        return text
    
    def load_all_resources(self, res_dir: str) -> bool:
        """
        加载所有语言的字符串资源
        
        Args:
            res_dir: Android资源目录路径
            
        Returns:
            bool: 是否成功加载
        """
        strings_files = self.find_strings_files(res_dir)
        if not strings_files:
            self.logger.error("未找到任何strings.xml文件")
            return False
            
        self.resource_map = {}
        for lang_code, file_path in strings_files.items():
            strings = self.parse_strings_xml(file_path)
            if strings:
                self.resource_map[lang_code] = strings
                
        self.logger.info(f"成功加载 {len(self.resource_map)} 种语言的资源")
        return len(self.resource_map) > 0
    
    def find_by_names(self, names: List[str]) -> Dict[str, Dict[str, str]]:
        """
        模式A: 根据资源名称查找
        
        Args:
            names: 资源名称列表
            
        Returns:
            Dict[str, Dict[str, str]]: 匹配的资源
        """
        result = {}
        name_set = set(names)
        
        for lang, strings in self.resource_map.items():
            matched = {name: value for name, value in strings.items() 
                      if name in name_set}
            if matched:
                result[lang] = matched
                
        return result
    
    def find_by_values(self, values: List[str], match_type: str = 'fuzzy') -> Dict[str, Dict[str, str]]:
        """
        模式B: 根据字符串值查找
        
        Args:
            values: 字符串值列表
            exact_match: 是否要求精确匹配
            
        Returns:
            Dict[str, Dict[str, str]]: 匹配的资源
        """
        result = {}
        matched_names = set()
        
        # 首先找到所有匹配的名称
        for value_to_find in values:
            for lang, strings in self.resource_map.items():
                for name, value in strings.items():
                    if match_type == 'exact':
                        # 精确匹配：要求完全相等
                        if value_to_find == value:
                            matched_names.add(name)
                            self.logger.info(f"找到匹配项: {name}: {value}")
                    else:
                        # 模糊匹配：部分包含
                        if value_to_find in value:
                            matched_names.add(name)
                            self.logger.info(f"找到匹配项: {name}: {value}")
        
        # 然后收集所有语言中这些名称的资源
        for lang, strings in self.resource_map.items():
            matched = {name: value for name, value in strings.items() 
                      if name in matched_names}
            if matched:
                result[lang] = matched
                
        return result
    
    def find_by_language_qualified(self, qualified_ids: List[str]) -> Dict[str, Dict[str, str]]:
        """
        模式C: 根据语言限定标识查找
        
        Args:
            qualified_ids: 语言限定标识列表，格式如"zh:app_name"
            
        Returns:
            Dict[str, Dict[str, str]]: 匹配的资源
        """
        result = {}
        all_matched_names = set()
        
        for qualified_id in qualified_ids:
            if ':' not in qualified_id:
                self.logger.warning(f"无效的语言限定标识: {qualified_id}")
                continue
                
            target_lang, name = qualified_id.split(':', 1)
            
            # 查找匹配的语言代码
            matching_langs = [lang for lang in self.resource_map.keys() 
                            if lang.startswith(target_lang) or lang == target_lang]
            
            if not matching_langs:
                self.logger.warning(f"未找到语言 {target_lang} 的资源")
                continue
                
            # 优先使用完全匹配的语言
            if target_lang in matching_langs:
                preferred_lang = target_lang
            else:
                preferred_lang = matching_langs[0]
                
            if preferred_lang in self.resource_map and name in self.resource_map[preferred_lang]:
                all_matched_names.add(name)
                
        # 收集所有语言中匹配名称的资源
        for lang, strings in self.resource_map.items():
            matched = {name: value for name, value in strings.items() 
                      if name in all_matched_names}
            if matched:
                result[lang] = matched
                
        return result
    
    def generate_harmony_resources(self, matched_resources: Dict[str, Dict[str, str]], 
                                 output_dir: str) -> bool:
        """
        生成鸿蒙格式的JSON资源文件
        
        Args:
            matched_resources: 匹配的资源
            output_dir: 输出目录
            
        Returns:
            bool: 是否成功生成
        """
        try:
            output_path = Path(output_dir)
            output_path.mkdir(parents=True, exist_ok=True)
            
            for lang, strings in matched_resources.items():
                # 创建语言目录结构
                if lang == 'base':
                    lang_dir = output_path / 'resources' / 'base' / 'element'
                else:
                    lang_dir = output_path / 'resources' / lang / 'element'
                    
                lang_dir.mkdir(parents=True, exist_ok=True)
                
                # 生成JSON内容
                json_content = {
                    "string": [
                        {"name": name, "value": value}
                        for name, value in strings.items()
                    ]
                }
                
                # 写入JSON文件
                json_file = lang_dir / 'string.json'
                with open(json_file, 'w', encoding='utf-8') as f:
                    json.dump(json_content, f, ensure_ascii=False, indent=2)
                    
                self.logger.info(f"生成 {json_file}: {len(strings)} 个字符串")
                
            return True
            
        except Exception as e:
            self.logger.error(f"生成鸿蒙资源文件时出错: {e}")
            return False


class MigratorGUI:
    """GUI界面类"""
    
    def __init__(self):
        self.migrator = ResourceMigrator()
        self.root = tk.Tk()
        self.setup_ui()
        
    def setup_ui(self):
        """设置UI界面"""
        self.root.title("Android到鸿蒙字符串资源转换工具")
        self.root.geometry("800x600")
        
        # 创建主框架
        main_frame = ttk.Frame(self.root, padding="10")
        main_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
        
        # 配置网格权重
        self.root.columnconfigure(0, weight=1)
        self.root.rowconfigure(0, weight=1)
        main_frame.columnconfigure(1, weight=1)
        
        # 输入目录选择
        ttk.Label(main_frame, text="Android资源目录:").grid(row=0, column=0, sticky=tk.W, pady=5)
        self.dir_var = tk.StringVar()
        ttk.Entry(main_frame, textvariable=self.dir_var, width=50).grid(row=0, column=1, sticky=(tk.W, tk.E), padx=5)
        ttk.Button(main_frame, text="浏览", command=self.browse_directory).grid(row=0, column=2, padx=5)
        
        # 转换模式选择
        ttk.Label(main_frame, text="转换模式:").grid(row=1, column=0, sticky=tk.W, pady=5)
        self.mode_var = tk.StringVar(value="names")
        mode_frame = ttk.Frame(main_frame)
        mode_frame.grid(row=1, column=1, sticky=(tk.W, tk.E), pady=5)
        
        ttk.Radiobutton(mode_frame, text="按资源名称", variable=self.mode_var, value="names").pack(side=tk.LEFT)
        ttk.Radiobutton(mode_frame, text="按字符串值", variable=self.mode_var, value="values").pack(side=tk.LEFT, padx=10)
        ttk.Radiobutton(mode_frame, text="按语言限定", variable=self.mode_var, value="qualified").pack(side=tk.LEFT)
        
        # 匹配模式选择
        ttk.Label(main_frame, text="匹配模式:").grid(row=2, column=0, sticky=tk.W, pady=5)
        self.match_type_var = tk.StringVar(value="fuzzy")
        match_frame = ttk.Frame(main_frame)
        match_frame.grid(row=2, column=1, sticky=(tk.W, tk.E), pady=5)
        
        ttk.Radiobutton(match_frame, text="模糊匹配", variable=self.match_type_var, value="fuzzy").pack(side=tk.LEFT)
        ttk.Radiobutton(match_frame, text="精确匹配", variable=self.match_type_var, value="exact").pack(side=tk.LEFT, padx=10)
        
        # 输入内容
        ttk.Label(main_frame, text="输入内容:").grid(row=3, column=0, sticky=(tk.W, tk.N), pady=5)
        self.input_text = scrolledtext.ScrolledText(main_frame, height=8, width=50)
        self.input_text.grid(row=3, column=1, sticky=(tk.W, tk.E, tk.N, tk.S), pady=5)
        
        # 帮助文本
        help_text = """
        输入说明:
        • 按资源名称: 每行一个资源名称，如 app_name
        • 按字符串值: 每行一个要搜索的字符串值，如 Welcome
        • 按语言限定: 每行一个语言限定标识，如 zh:app_name
        
        匹配模式说明:
        • 模糊匹配: 包含目标字符串的值（如"分析"匹配"财务分析"）
        • 精确匹配: 完全相同的字符串值（大小写敏感）
        """
        
        help_label = ttk.Label(main_frame, text=help_text, justify=tk.LEFT, foreground="gray")
        help_label.grid(row=3, column=2, sticky=(tk.W, tk.N), padx=10, pady=5)
        
        # 输出目录
        ttk.Label(main_frame, text="输出目录:").grid(row=4, column=0, sticky=tk.W, pady=5)
        self.output_var = tk.StringVar(value="harmony_resources")
        ttk.Entry(main_frame, textvariable=self.output_var, width=50).grid(row=4, column=1, sticky=(tk.W, tk.E), padx=5)
        
        # 按钮
        button_frame = ttk.Frame(main_frame)
        button_frame.grid(row=5, column=0, columnspan=3, pady=20)
        
        ttk.Button(button_frame, text="开始转换", command=self.start_conversion).pack(side=tk.LEFT, padx=5)
        ttk.Button(button_frame, text="清空日志", command=self.clear_log).pack(side=tk.LEFT, padx=5)
        
        # 日志显示
        ttk.Label(main_frame, text="转换日志:").grid(row=6, column=0, sticky=(tk.W, tk.N), pady=(20, 5))
        self.log_text = scrolledtext.ScrolledText(main_frame, height=12, width=80)
        self.log_text.grid(row=6, column=1, columnspan=2, sticky=(tk.W, tk.E, tk.N, tk.S), pady=(20, 0))
        
        # 配置行权重
        main_frame.rowconfigure(3, weight=1)
        main_frame.rowconfigure(6, weight=2)
        
        # 重定向日志到GUI
        self.setup_log_handler()
        
    def setup_log_handler(self):
        """设置日志处理器，将日志输出到GUI"""
        class GUILogHandler(logging.Handler):
            def __init__(self, text_widget):
                super().__init__()
                self.text_widget = text_widget
                
            def emit(self, record):
                msg = self.format(record)
                self.text_widget.insert(tk.END, msg + '\n')
                self.text_widget.see(tk.END)
                self.text_widget.update()
                
        handler = GUILogHandler(self.log_text)
        formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
        handler.setFormatter(formatter)
        
        self.migrator.logger.addHandler(handler)
        
    def browse_directory(self):
        """浏览目录"""
        directory = filedialog.askdirectory(title="选择Android项目的res目录")
        if directory:
            self.dir_var.set(directory)
            
    def clear_log(self):
        """清空日志"""
        self.log_text.delete(1.0, tk.END)
        
    def start_conversion(self):
        """开始转换"""
        # 在新线程中执行转换，避免阻塞UI
        thread = threading.Thread(target=self._do_conversion)
        thread.daemon = True
        thread.start()
        
    def _do_conversion(self):
        """执行转换逻辑"""
        try:
            # 获取输入参数
            res_dir = self.dir_var.get().strip()
            mode = self.mode_var.get()
            match_type = self.match_type_var.get()
            input_content = self.input_text.get(1.0, tk.END).strip()
            output_dir = self.output_var.get().strip()
            
            if not res_dir:
                messagebox.showerror("错误", "请选择Android资源目录")
                return
                
            if not input_content:
                messagebox.showerror("错误", "请输入要转换的内容")
                return
                
            # 解析输入内容
            input_lines = [line.strip() for line in input_content.split('\n') if line.strip()]
            
            # 加载资源
            self.migrator.logger.info("开始加载Android资源...")
            if not self.migrator.load_all_resources(res_dir):
                messagebox.showerror("错误", "加载Android资源失败")
                return
                
            # 根据模式查找资源
            self.migrator.logger.info(f"使用模式: {mode}")
            if match_type != 'fuzzy':
                self.migrator.logger.info(f"匹配类型: {match_type}")
            
            if mode == "names":
                matched_resources = self.migrator.find_by_names(input_lines)
            elif mode == "values":
                matched_resources = self.migrator.find_by_values(input_lines, match_type)
            elif mode == "qualified":
                matched_resources = self.migrator.find_by_language_qualified(input_lines)
            else:
                messagebox.showerror("错误", "无效的转换模式")
                return
                
            if not matched_resources:
                messagebox.showwarning("警告", "未找到匹配的资源")
                return
                
            # 显示匹配结果
            total_strings = sum(len(strings) for strings in matched_resources.values())
            self.migrator.logger.info(f"找到 {len(matched_resources)} 种语言，共 {total_strings} 个字符串")
            
            # 生成鸿蒙资源
            self.migrator.logger.info("开始生成鸿蒙资源文件...")
            if self.migrator.generate_harmony_resources(matched_resources, output_dir):
                messagebox.showinfo("成功", f"转换完成！资源已保存到: {output_dir}")
            else:
                messagebox.showerror("错误", "生成鸿蒙资源文件失败")
                
        except Exception as e:
            self.migrator.logger.error(f"转换过程中出错: {e}")
            messagebox.showerror("错误", f"转换失败: {e}")
            
    def run(self):
        """运行GUI"""
        self.root.mainloop()


def run_cli():
    """命令行模式"""
    parser = argparse.ArgumentParser(description='Android字符串资源到鸿蒙字符串资源转换工具')
    parser.add_argument('res_dir', help='Android项目的res目录路径')
    parser.add_argument('--mode', choices=['names', 'values', 'qualified'], 
                       default='names', help='转换模式 (默认: names)')
    parser.add_argument('--input', required=True, 
                       help='输入内容，多个值用逗号分隔')
    parser.add_argument('--output', default='harmony_resources',
                       help='输出目录 (默认: harmony_resources)')
    parser.add_argument('--match-type', choices=['exact', 'fuzzy'], 
                       default='fuzzy', help='字符串匹配模式 (默认: fuzzy)')
    parser.add_argument('--verbose', '-v', action='store_true',
                       help='显示详细日志')
    
    args = parser.parse_args()
    
    # 设置日志级别
    if args.verbose:
        logging.getLogger().setLevel(logging.DEBUG)
    
    # 创建迁移器
    migrator = ResourceMigrator()
    
    # 加载资源
    print(f"正在加载Android资源: {args.res_dir}")
    if not migrator.load_all_resources(args.res_dir):
        print("错误: 加载Android资源失败")
        return 1
        
    # 解析输入
    input_items = [item.strip() for item in args.input.split(',') if item.strip()]
    
    # 根据模式查找资源
    print(f"使用模式: {args.mode}")
    if args.match_type != 'fuzzy':
        print(f"匹配类型: {args.match_type}")
    
    if args.mode == 'names':
        matched_resources = migrator.find_by_names(input_items)
    elif args.mode == 'values':
        matched_resources = migrator.find_by_values(input_items, args.match_type)
    elif args.mode == 'qualified':
        matched_resources = migrator.find_by_language_qualified(input_items)
    
    if not matched_resources:
        print("警告: 未找到匹配的资源")
        return 1
        
    # 显示匹配结果
    total_strings = sum(len(strings) for strings in matched_resources.values())
    print(f"找到 {len(matched_resources)} 种语言，共 {total_strings} 个字符串:")
    
    for lang, strings in matched_resources.items():
        print(f"  {lang}: {len(strings)} 个字符串")
        
    # 生成鸿蒙资源
    print(f"正在生成鸿蒙资源到: {args.output}")
    if migrator.generate_harmony_resources(matched_resources, args.output):
        print("转换完成！")
        return 0
    else:
        print("错误: 生成鸿蒙资源失败")
        return 1


def main():
    """主入口函数"""
    import sys
    
    if len(sys.argv) == 1:
        # 无参数时启动GUI
        print("启动GUI模式...")
        gui = MigratorGUI()
        gui.run()
    else:
        # 有参数时使用CLI模式
        sys.exit(run_cli())


if __name__ == "__main__":
    main()
